﻿namespace ScrumLite.Services.Tests
{
    using System;
    using System.Collections.Generic;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using ScrumLite.Services.Contracts;
    using Rhino.Mocks;
    using System.Linq;

    [TestClass]
    public class LinqDefectsServiceFixture
    {
        MockRepository mocks;

        [TestInitialize]
        public void Initialize()
        {
            this.mocks = new MockRepository();
        }

        [TestMethod()]
        public void ShouldSaveDefects()
        {
            ScrumLite.Data.IDefectStore store = this.mocks.DynamicMock<ScrumLite.Data.IDefectStore>();
            List<ScrumLite.Data.Defect> actual = new List<ScrumLite.Data.Defect>();

            // set an expectation that will do a callback and set the argument 
            // to a local member to perform Asserts later
            // repeat the expectation twice because we will save two defects, hence expect two calls to Update
            Expect.Call(() => store.Update(null))
                .Callback(new Func<ScrumLite.Data.Defect, bool>(r => { actual.Add(r); return true; }))
                .Repeat.Times(2);
            mocks.ReplayAll();

            LinqDefectsService service = new LinqDefectsService(store);
            Defect[] defects = new Defect[] { 
                new Defect { Id = Guid.NewGuid(), Decision = "Action 1", CreatedBy = "User1", CreatedOn = DateTime.Now, DaysOpen = 0, DeliverableId = new Guid(), Moniker = 1, Notes = "Some Notes", Severity = 2, Title = "Title", Triaged = false, TriagedOn = null },
                new Defect { Id = Guid.NewGuid(), Decision = "Action 2", CreatedBy = "User2", CreatedOn = DateTime.Now, DaysOpen = 0, DeliverableId = new Guid(), Moniker = 21, Notes = "Some Notes2", Severity = 2, Title = "Title", Triaged = true, TriagedOn = DateTime.Now },
            };
            service.SaveDefects(defects);

            Assert.AreEqual(defects.Length, actual.Count);
            for (int i = 0; i < defects.Length; i++)
            {
                Assert.AreEqual(defects[i].Id, actual[i].id);
                Assert.AreEqual(defects[i].CreatedBy, actual[i].user_createdBy);
                Assert.AreEqual(defects[i].CreatedOn, actual[i].createdOn);
                Assert.AreEqual(defects[i].Decision, actual[i].decision);
                Assert.AreEqual(defects[i].DeliverableId, actual[i].fk_deliverable);
                Assert.AreEqual(defects[i].Moniker, actual[i].moniker);
                Assert.AreEqual(defects[i].Notes, actual[i].notes);
                Assert.AreEqual((byte?)defects[i].Severity, actual[i].severity);
                Assert.AreEqual(defects[i].Title, actual[i].title);
                Assert.AreEqual(defects[i].TriagedOn, actual[i].triagedOn);
            }
        }


        [TestMethod]
        public void ShouldAddDefect()
        {
            ScrumLite.Data.IDefectStore store = this.mocks.DynamicMock<ScrumLite.Data.IDefectStore>();
            ScrumLite.Data.Defect actual = null;

            // set an expectation that will do a callback and set the argument 
            // to a local member to perform Asserts later
            Expect.Call(() => store.Add(null))
                .Callback(new Func<ScrumLite.Data.Defect, bool>(r => { actual = r; return true; }));
            Expect.Call(store.RetrieveLastMoniker(Guid.Empty))
                .Return(99)
                .Callback(new Func<Guid, bool>(r => { return true; }));
            mocks.ReplayAll();

            LinqDefectsService service = new LinqDefectsService(store);

            Guid projectId = Guid.NewGuid();
            Defect expected = new Defect { Id = Guid.NewGuid(), Moniker = service.GetNextMoniker(projectId.ToString()), Notes = "Some notes", Title = "Some title", CreatedOn = new DateTime(2008, 11, 23), TriagedOn = new DateTime(2008, 11, 24), CreatedBy = "User", Severity = 10, DeliverableId = new Guid(), Decision = "A decision" };
            service.AddDefect(expected);

            Assert.AreEqual(expected.Id, actual.id);
            Assert.AreEqual(expected.CreatedBy, actual.user_createdBy);
            Assert.AreEqual(expected.CreatedOn, actual.createdOn);
            Assert.AreEqual(expected.Decision, actual.decision);
            Assert.AreEqual(expected.DeliverableId, actual.fk_deliverable);
            Assert.AreEqual(expected.Moniker, actual.moniker);
            Assert.AreEqual(expected.Notes, actual.notes);
            Assert.AreEqual((byte?)expected.Severity, actual.severity);
            Assert.AreEqual(expected.Title, actual.title);
            Assert.AreEqual(expected.TriagedOn, actual.triagedOn);
        }

        [TestMethod]
        public void ShouldUpdateDefect()
        {
            ScrumLite.Data.IDefectStore store = this.mocks.DynamicMock<ScrumLite.Data.IDefectStore>();
            ScrumLite.Data.Defect actual = null;

            // set an expectation that will do a callback and set the argument 
            // to a local member to perform Asserts later
            Expect.Call(() => store.Update(null))
                .Callback(new Func<ScrumLite.Data.Defect, bool>(d => { actual = d; return true; }));
            mocks.ReplayAll();

            LinqDefectsService service = new LinqDefectsService(store);

            Defect expected = new Defect { Id = Guid.NewGuid(), Decision = "Decision made", CreatedBy = "user 1", Moniker = 100, Notes = "Some notes", Severity = 3, Title = "Some title", CreatedOn = DateTime.Today };
            service.UpdateDefect(expected);

            Assert.AreEqual(expected.Id, actual.id);
            Assert.AreEqual(expected.Moniker, actual.moniker);
            Assert.AreEqual(expected.Notes, actual.notes);
            Assert.AreEqual(expected.CreatedBy, actual.user_createdBy);
            Assert.AreEqual((byte?)expected.Severity, actual.severity);
            Assert.AreEqual(expected.Decision, actual.decision);
            Assert.AreEqual(expected.Title, actual.title);
            Assert.AreEqual(expected.DeliverableId, actual.fk_deliverable);
            Assert.AreEqual(DateTime.Now.Date, actual.createdOn.Date);

        }

        [TestMethod]
        public void ShouldDeleteDefect()
        {
            ScrumLite.Data.IDefectStore store = this.mocks.DynamicMock<ScrumLite.Data.IDefectStore>();
            Guid actual = Guid.Empty;

            // set an expectation that will do a callback and set the argument 
            // to a local member to perform Asserts later
            Expect.Call(() => store.Delete(Guid.Empty))
                .Callback(new Func<Guid, bool>(g => { actual = g; return true; }));
            mocks.ReplayAll();

            LinqDefectsService service = new LinqDefectsService(store);

            Guid expected = Guid.NewGuid();
            service.DeleteDefect(expected);

            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void ShouldGetDefects()
        {
            ScrumLite.Data.IDefectStore store = this.mocks.DynamicMock<ScrumLite.Data.IDefectStore>();
            Defect[] actual = null;
            ScrumLite.Data.Defect[] expected = new ScrumLite.Data.Defect[] { new ScrumLite.Data.Defect { createdOn= DateTime.Today, decision="Some decision", severity = 1, title="Title", triagedOn=DateTime.Today, id=Guid.NewGuid(), user_createdBy="southy" } };
            
            Guid projectUri = Guid.NewGuid();
            // set an expectation that will do a callback and set the argument 
            // to a local member to perform Asserts later
            Expect.Call(store.RetrieveDefects(projectUri, true))
                .Return(expected)
                .Callback(new Func<Guid, bool, bool>((c,t) => { return true; }));
            mocks.ReplayAll();

            LinqDefectsService service = new LinqDefectsService(store);
            byte triaged = 1;
            actual = service.GetDefects(projectUri.ToString(),triaged).ToArray();

            Assert.AreEqual(expected.Length, actual.Length);

            for (int i = 0; i < expected.Length; i++)
            {
                Assert.AreEqual(expected[i].user_createdBy, actual[i].CreatedBy);
                Assert.AreEqual(expected[i].createdOn, actual[i].CreatedOn);
                Assert.AreEqual(expected[i].triagedOn, actual[i].TriagedOn);
                Assert.AreEqual(expected[i].decision, actual[i].Decision);
                Assert.AreEqual(expected[i].title, actual[i].Title);
                Assert.AreEqual(expected[i].severity, (byte?) actual[i].Severity);
            }
        }

        [TestMethod]
        public void ShouldGetNotTriagedDefects()
        {
            ScrumLite.Data.IDefectStore store = this.mocks.DynamicMock<ScrumLite.Data.IDefectStore>();
            Defect[] actual = null;
            ScrumLite.Data.Defect[] expected = new ScrumLite.Data.Defect[] {
            new ScrumLite.Data.Defect { createdOn = DateTime.Today, decision = "Some decision", severity = 1, title = "Title2", triagedOn = null, id = Guid.NewGuid(), user_createdBy = "southy" }
            };

            Guid projectUri = Guid.NewGuid();
            // set an expectation that will do a callback and set the argument 
            // to a local member to perform Asserts later
            Expect.Call(store.RetrieveDefects(projectUri, false))
                .Return(expected)
                .Callback(new Func<Guid, bool, bool>((c,t) => { return true; }));
            mocks.ReplayAll();

            LinqDefectsService service = new LinqDefectsService(store);
            byte triaged = 0;
            actual = service.GetDefects(projectUri.ToString(), triaged).ToArray();

            Assert.AreEqual(expected.Length, actual.Length);

            for (int i = 0; i < expected.Length; i++)
            {
                Assert.AreEqual(expected[i].user_createdBy, actual[i].CreatedBy);
                Assert.AreEqual(expected[i].createdOn, actual[i].CreatedOn);
                Assert.AreEqual(expected[i].triagedOn, actual[i].TriagedOn);
                Assert.AreEqual(expected[i].decision, actual[i].Decision);
                Assert.AreEqual(expected[i].title, actual[i].Title);
                Assert.AreEqual(expected[i].severity, (byte?)actual[i].Severity);
            }

        }

        [TestMethod]
        public void ShouldGetDefectByProjectIdAndMoniker()
        {
            ScrumLite.Data.IDefectStore store = this.mocks.DynamicMock<ScrumLite.Data.IDefectStore>();
            ScrumLite.Data.Deliverable deliverable = new ScrumLite.Data.Deliverable() { id = Guid.NewGuid() };
            ScrumLite.Data.Defect expected = new ScrumLite.Data.Defect { id = Guid.NewGuid(), moniker = 100, notes = "Some notes", title = "Some title", createdOn = new DateTime(2008, 11, 23), triagedOn = new DateTime(2008, 11, 24), user_createdBy = "User", severity = 10, fk_deliverable = new Guid(), decision = "A decision", Deliverable = deliverable };
            // set an expectation that will do a callback and set the argument 
            // to a local member to perform Asserts later 
            Expect.Call(store.RetrieveDefect(null, 0))
            .Return(expected)
            .Callback(
            new Func<string, int, bool>((a, b) => { return true; }));
            mocks.ReplayAll();
            LinqDefectsService service = new LinqDefectsService(store);
            Guid projectId = Guid.NewGuid();
            Defect actual = service.GetDefect(projectId.ToString(), 100);
            Assert.AreEqual(expected.id, actual.Id);
            Assert.AreEqual(expected.user_createdBy, actual.CreatedBy);
            Assert.AreEqual(expected.createdOn, actual.CreatedOn);
            Assert.AreEqual(expected.decision, actual.Decision);
            Assert.AreEqual(expected.fk_deliverable, actual.DeliverableId);
            Assert.AreEqual(expected.moniker, actual.Moniker);
            Assert.AreEqual(expected.notes, actual.Notes);
            Assert.AreEqual(expected.severity, (byte?)actual.Severity);
            Assert.AreEqual(expected.title, actual.Title);
            Assert.AreEqual(expected.triagedOn, actual.TriagedOn);
            Assert.AreEqual(expected.triagedOn.HasValue, actual.Triaged);
        }


        [TestMethod]
        public void ShouldGetDefectsByDeliverable()
        {
            ScrumLite.Data.IDefectStore store = this.mocks.DynamicMock<ScrumLite.Data.IDefectStore>();

            Guid projectUri = Guid.NewGuid();
            string deliverableId = "5ab41697-8a18-4254-9d13-2ca8e93504a0";

            Defect[] actual = null;
            ScrumLite.Data.Defect[] expected = new ScrumLite.Data.Defect[] 
            {
                new ScrumLite.Data.Defect 
                { 
                    createdOn = DateTime.Today, 
                    decision = "Some decision",
                    severity = 1, 
                    title = "Title", 
                    triagedOn = DateTime.Today, 
                    id = Guid.NewGuid(), 
                    user_createdBy = "southy",
                    fk_deliverable = new Guid(deliverableId)
                } 
            };

            // set an expectation that will do a callback and set the argument 
            // to a local member to perform Asserts later
            Expect.Call(store.RetrieveDefects(projectUri, true))
                .Return(expected)
                .Callback(new Func<Guid, bool, bool>((c,t) => { return true; }));
            mocks.ReplayAll();

            LinqDefectsService service = new LinqDefectsService(store);

            actual = service.GetDefectsByDeliverable(projectUri.ToString(), deliverableId);

            Assert.AreEqual(expected.Length, actual.Length);

            for (int i = 0; i < expected.Length; i++)
            {
                Assert.AreEqual(expected[i].user_createdBy, actual[i].CreatedBy);
                Assert.AreEqual(expected[i].createdOn, actual[i].CreatedOn);
                Assert.AreEqual(expected[i].triagedOn, actual[i].TriagedOn);
                Assert.AreEqual(expected[i].decision, actual[i].Decision);
                Assert.AreEqual(expected[i].title, actual[i].Title);
                Assert.AreEqual(expected[i].severity, (byte?)actual[i].Severity);
            }
        }

    }
}
